/*
 * @(#)$Id: StringUtils.java 3619 2008-03-26 07:23:03Z yui $
 * 
 * Copyright 2006-2008 Makoto YUI
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 * 
 * Contributors: Makoto YUI - initial implementation
 */
package jacky.lanlan.song.lang;

import jacky.lanlan.song.io.bit.Primitives;

/**
 * 
 * @author Makoto YUI (yuin405+xbird@gmail.com)
 */
public abstract class BitStringUtils {

	public static String toBitString(final double d) {
		final char[] bit = new char[64];
		final long dd = Double.doubleToLongBits(d);
		long mask = 1L;
		for (int i = 0; i < 64; i++) {
			final long bitval = dd & mask;
			if (bitval == 0) {
				bit[63 - i] = '0';
			}
			else {
				bit[63 - i] = '1';
			}
			mask <<= 1;
		}
		return String.valueOf(bit);
	}

	public static String toBitString(final float f) {
		final char[] bit = new char[32];
		final int ff = Float.floatToIntBits(f);
		int mask = 1;
		for (int i = 0; i < 32; i++) {
			final int bitval = ff & mask;
			if (bitval == 0) {
				bit[31 - i] = '0';
			}
			else {
				bit[31 - i] = '1';
			}
			mask <<= 1;
		}
		return String.valueOf(bit);
	}

	public static String toBitString(final long n) {
		final char[] bit = new char[64];
		long mask = 1L;
		for (int i = 0; i < 64; i++) {
			final long bitval = n & mask;
			if (bitval == 0) {
				bit[63 - i] = '0';
			}
			else {
				bit[63 - i] = '1';
			}
			mask <<= 1;
		}
		return String.valueOf(bit);
	}

	public static String toBitString(final int n) {
		final char[] bit = new char[32];
		int mask = 1;
		for (int i = 0; i < 32; i++) {
			final int bitval = n & mask;
			if (bitval == 0) {
				bit[31 - i] = '0';
			}
			else {
				bit[31 - i] = '1';
			}
			mask <<= 1;
		}
		return String.valueOf(bit);
	}

	public static String toBitString(final byte[] b) {
		final char[] bits = new char[8 * b.length];
		for (int i = 0; i < b.length; i++) {
			final byte byteval = b[i];
			int bytei = i << 3;
			int mask = 0x1;
			for (int j = 7; j >= 0; j--) {
				final int bitval = byteval & mask;
				if (bitval == 0) {
					bits[bytei + j] = '0';
				}
				else {
					bits[bytei + j] = '1';
				}
				mask <<= 1;
			}
		}
		return String.valueOf(bits);
	}

	public static byte[] getBytes(final String s) {
		assert (s != null);
		final int len = s.length();
		final byte[] b = new byte[len * 2];
		for (int i = 0; i < len; i++) {
			Primitives.putChar(b, i * 2, s.charAt(i));
		}
		return b;
	}

	public static String toString(byte[] b) {
		return toString(b, 0, b.length);
	}

	public static String toString(byte[] b, int off, int len) {
		final int clen = len >>> 1;
		final char[] c = new char[clen];
		for (int i = 0; i < clen; i++) {
			final int j = off + (i << 1);
			c[i] = (char) ((b[j + 1] & 0xFF) + ((b[j + 0]) << 8));
		}
		return new String(c);
	}

	private static final float KBYTES = 1024f;

	private static final float MBYTES = KBYTES * KBYTES;

	private static final float GBYTES = MBYTES * KBYTES;

	public static String displayBytesSize(final long n) {
		final String size;
		final long abs = Math.abs(n);
		if (abs < KBYTES) {
			size = n + " bytes";
		}
		else if (abs < MBYTES) {
			size = String.format("%.2f", n / KBYTES) + " kB";
		}
		else if (abs < GBYTES) {
			size = String.format("%.2f", n / MBYTES) + " MB";
		}
		else {
			return String.format("%.2f", n / GBYTES) + " GB";
		}
		return size;
	}

	private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();

	private static final int UPPER_NIBBLE_MASK = 0xF0;

	private static final int LOWER_NIBBLE_MASK = 0x0F;

	public static void encodeHex(final byte b, final StringBuilder buf) {
		final int upper = (b & UPPER_NIBBLE_MASK) >> 4;
		final int lower = b & LOWER_NIBBLE_MASK;
		buf.append(HEX_DIGITS[upper]);
		buf.append(HEX_DIGITS[lower]);
	}

	public static String encodeHex(final byte buf[]) {
		final int buflen = buf.length;
		final char[] ch = new char[buflen * 2];
		for (int i = 0, j = 0; i < buf.length; i++, j += 2) {
			final byte b = buf[i];
			final int upper = (b & UPPER_NIBBLE_MASK) >> 4;
			final int lower = b & LOWER_NIBBLE_MASK;
			ch[j] = HEX_DIGITS[upper];
			ch[j + 1] = HEX_DIGITS[lower];
		}
		return new String(ch);
	}

}
